package org.jleaf.springcloud.webui.controller;

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.jleaf.springcloud.webui.service.AccountService;
import org.jleaf.springcloud.webui.service.UserService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletRequest;
import java.io.FileOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicLong;

/**
 * @author yaoshuhong
 * @date 2016-08-03 15:34
 */
@RestController
@RequestMapping("user")
public class UserController {

    private static Logger log = LoggerFactory.getLogger(UserController.class);

    private static AtomicLong atomicLong = new AtomicLong();

    /**
     * 需要依赖WebUIApplication那定义好构建
     */
    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private UserService userService;

    @Autowired
    private AccountService accountService;

    @RequestMapping("file")
    public String file(MultipartFile file, HttpServletRequest request) {

        Enumeration<String> headerNames = request.getHeaderNames();
        while (headerNames.hasMoreElements()) {
            String name = headerNames.nextElement();
            log.info("{}:{}", name, request.getHeader(name));
        }

        log.info("file:{}", file.getOriginalFilename());

        String name = "E:/abc/" + file.getOriginalFilename();
        FileOutputStream output = null;
        try {
            Path path = Paths.get(name);
            if (Files.notExists(path)) {
                Files.createFile(path);
            }
            output = new FileOutputStream(name);
            IOUtils.copy(file.getInputStream(), output);
            output.close();
        } catch (Exception e) {
            log.error("upload error", e);
            return "error";
        } finally {
            IOUtils.closeQuietly(output);
        }
        return "ok";
    }

    @RequestMapping("test")
    public String test() {
        log.info("request....");
        return "abc";
    }

    /*****采用RestTemplate方式去调用****/
    @RequestMapping("basicInfo")
    public Object basicInfo(Long id, String status) {
        return restTemplate.getForObject("http://USERSERVICE/basicInfo?id=" + id + "&status=" + status, Map.class);
    }

    @RequestMapping("account")
    public Object account(Long id) {
        return restTemplate.getForObject("http://ACCOUNTSERVICE/balance?id=" + id, Double.class);
    }

    /********采用Feign方式去调用(推荐)*******/
    @RequestMapping("basicInfo2")
    @HystrixCommand(fallbackMethod = "basicInfo3Fail")
    public Object basicInfo2(String id, String username) {
        log.info("id:{}, username:{}", id, username);
        return userService.basicInfo(1L, "2");
    }

    @RequestMapping("account2")
    public Object account2() {
        return accountService.balance(1L);
    }

    /********模拟断路器的熔断机制********/
    @RequestMapping("basicInfo3")
    @HystrixCommand(fallbackMethod = "basicInfo3Fail")
    public Object basicInfo3(String id, String username) {
        return restTemplate.getForObject("http://USERSERVICE/xxxxxxx", Map.class);//故意调用不存在的接口,保证调用失败
    }

    /**
     * 因为basicInfo3方法上配置了断路器,在调用失败时会自动调用basicInfo3方法, 必须保证方法入参一毛一样
     *
     * @param id
     * @param username
     * @return
     */
    public Object basicInfo3Fail(String id, String username, Throwable e) {
        long count = atomicLong.addAndGet(1);
        log.error("error:", e);
        log.info("调用失败,第{}次", count);
        Map model = new HashMap<>();
        model.put("id", id);
        model.put("username", username);
        model.put("msg", "调用失败");
        return model;
    }
}
